{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Deploys model to KFServing\n",
    "Note: As this is running inside a KF Pipeline you need to grant additional permissions:\n",
    "\n",
    "kubectl create clusterrolebinding pipeline-runner-extend --clusterrole cluster-admin --serviceaccount=kubeflow:pipeline-runner (Kudos to Tommy Li https://github.com/Tomcli)\n",
    "\n",
    "and also inject the storage initializer into the control plane namespace\n",
    "https://github.com/kubeflow/kfserving/issues/1389"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip3 install kfp-tekton\n",
    "!pip3 install kfserving==0.4.1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from kfserving import constants\n",
    "from kfserving import KFServingClient\n",
    "from kfserving import utils\n",
    "from kfserving import V1alpha2EndpointSpec\n",
    "from kfserving import V1alpha2InferenceService\n",
    "from kfserving import V1alpha2InferenceServiceSpec\n",
    "from kfserving import V1alpha2PredictorSpec\n",
    "from kfserving import V1alpha2TensorflowSpec\n",
    "from kubernetes import client\n",
    "from kubernetes.client import V1ResourceRequirements\n",
    "import os"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# @param model_name How the model should be named on KFServing\n",
    "# @param model_uri URI where the model can be downloaded from"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_name = os.environ.get('model_name')\n",
    "model_uri = os.environ.get('model_uri')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "constants.KFSERVING_VERSION"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define namespace where InferenceService needs to be deployed to. If not specified, below function defines namespace to the current one where SDK is running in the cluster, otherwise it will deploy to default namespace."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "namespace = utils.get_default_target_namespace()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define InferenceService"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Firstly define default endpoint spec, and then define the inferenceservice basic on the endpoint spec."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "api_version = constants.KFSERVING_GROUP + '/' + constants.KFSERVING_VERSION\n",
    "default_endpoint_spec = V1alpha2EndpointSpec(\n",
    "    predictor=V1alpha2PredictorSpec(\n",
    "        tensorflow=V1alpha2TensorflowSpec(\n",
    "            storage_uri=model_uri,\n",
    "            resources=V1ResourceRequirements(\n",
    "                requests={'cpu': '100m', 'memory': '1Gi'},\n",
    "                limits={'cpu': '100m', 'memory': '1Gi'}))))\n",
    "\n",
    "isvc = V1alpha2InferenceService(\n",
    "    api_version=api_version,\n",
    "    kind=constants.KFSERVING_KIND,\n",
    "    metadata=client.V1ObjectMeta(\n",
    "        name='flower-sample',\n",
    "        namespace=namespace\n",
    "    ),\n",
    "    spec=V1alpha2InferenceServiceSpec(default=default_endpoint_spec)\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "KFServing = KFServingClient()\n",
    "KFServing.delete(model_name, namespace=namespace)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create InferenceService"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Call KFServingClient to create InferenceService."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "KFServing = KFServingClient()\n",
    "KFServing.create(isvc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Check the InferenceService"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "KFServing.get(model_name, namespace=namespace, watch=True, timeout_seconds=120)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
